package com.devilvan.betrice.proxy.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.devilvan.betrice.exception.BetriceException;
import com.devilvan.betrice.exception.constant.BetriceExceptionConstant;
import com.devilvan.betrice.proxy.BetriceHttpProxy;
import com.devilvan.betrice.proxy.pojo.BetriceProxyDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author Evad.Wu
 * @Description 快代理 对象
 * @date 2022-08-12
 */
@Slf4j
//@Component
public class KdlProxy extends BetriceHttpProxy {
    @Value("$betrice.proxy.kuaidaili.url")
    public String proxyKuaidailiUrl;
    @Value("$betrice.proxy.kuaidaili.user-name")
    public String proxyUserName;
    @Value("$betrice.proxy.kuaidaili.password")
    public String proxyPassword;

    @Resource(name = "httpClientPool")
    private PoolingHttpClientConnectionManager connectionManager;

    /**
     * 被代理对象
     */
    private HttpRequestBase proxiedRequest;
    /**
     * 代理对象的IP+端口
     */
    public List<HttpHost> proxyHostList;



    public KdlProxy(@Autowired(required = false) HttpRequestBase proxiedRequest) {
        this.proxiedRequest = proxiedRequest;
    }

    @Override
    public List<BetriceProxyDto> run() {
        proxiedRequest = Optional.ofNullable(this.getProxiedRequest())
                .orElseThrow(() -> new BetriceException(BetriceExceptionConstant.PROXIED_IS_NULL_EXP.getMessage()));
        String json = this.requestProxy();
        List<BetriceProxyDto> betriceProxyDto = Optional.ofNullable(this.parseRequestJson(json))
                .orElseThrow(() -> new BetriceException(BetriceExceptionConstant.PROXY_INFO_INCORRECT_EXP.getMessage()));
        this.setProxyHost(proxiedRequest, betriceProxyDto);
        super.executeSaveProxy(betriceProxyDto);
        return betriceProxyDto;
    }

    @Override
    public HttpRequestBase getProxiedRequest() {
        return proxiedRequest;
    }

    @Override
    public String requestProxy() {
        HttpGet httpGet = new HttpGet(proxyKuaidailiUrl);
        CloseableHttpClient client = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .build();
        String resJson = null;
        CloseableHttpResponse response;
        try {
            response = client.execute(httpGet);
            HttpEntity responseEntity = response.getEntity();
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != statusCode) {
                throw new BetriceException(BetriceExceptionConstant.INTERNAL_SERVER_EXP.getMessage());
            }
            resJson = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(BetriceExceptionConstant.INTERNAL_SERVER_EXP.getMessage());
        }
        return resJson;
    }

    @Override
    public List<BetriceProxyDto> parseRequestJson(String requestJson) {
        JSONArray jsonArray = JSONObject.parseObject(requestJson).getJSONObject("data").getJSONArray("proxy_list");
        List<String> ipPorts = jsonArray.toJavaList(String.class);
        List<BetriceProxyDto> betriceProxyDtoList = new ArrayList<>();
        for (String ipPort : ipPorts) {
            String[] split = ipPort.split(":");
            String proxyIp = split[0];
            int proxyPort = Integer.parseInt(split[1]);
            BetriceProxyDto dto = new BetriceProxyDto(proxyIp, proxyPort);
            betriceProxyDtoList.add(dto);
        }
        return betriceProxyDtoList;
    }

    @Override
    public void setProxyHost(HttpRequestBase request, List<BetriceProxyDto> betriceProxyDtoList) {
        request = proxiedRequest;
        if (betriceProxyDtoList.size() == 1) {
            BetriceProxyDto betriceProxyDto = betriceProxyDtoList.get(0);
            HttpHost proxy = new HttpHost(betriceProxyDto.getIp(), betriceProxyDto.getPort());
            this.proxyHostList = List.of(proxy);
            RequestConfig requestConfig = RequestConfig.custom()
                    .setProxy(proxy)
                    .setConnectTimeout(10000)
                    .setSocketTimeout(10000)
                    .setConnectionRequestTimeout(6000)
                    .build();
            request.setConfig(requestConfig);
        }
    }

    @Override
    public List<HttpHost> getProxyHost() {
        return proxyHostList;
    }

    @Override
    public CredentialsProvider getCredentialsProvider(BetriceProxyDto betriceProxyDto) {
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(betriceProxyDto.getIp(), betriceProxyDto.getPort()),
                new UsernamePasswordCredentials(proxyUserName, proxyPassword));
        return credsProvider;
    }
}
